/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.cxf.tools.wsdlto.databinding.jaxb; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.StringReader; import java.io.StringWriter; import java.io.Writer; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.net.URI; import java.net.URL; import java.nio.file.Files; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; import java.util.logging.Level; import java.util.logging.Logger; import javax.xml.XMLConstants; import javax.xml.namespace.QName; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; import javax.xml.stream.util.StreamReaderDelegate; import javax.xml.transform.dom.DOMSource; import javax.xml.validation.SchemaFactory; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpression; import javax.xml.xpath.XPathFactory; import org.w3c.dom.Attr; import org.w3c.dom.DOMException; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.w3c.dom.ls.LSInput; import org.w3c.dom.ls.LSResourceResolver; import org.xml.sax.Attributes; import org.xml.sax.InputSource; import org.xml.sax.Locator; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import org.xml.sax.helpers.XMLFilterImpl; import com.sun.codemodel.ClassType; import com.sun.codemodel.CodeWriter; import com.sun.codemodel.JClass; import com.sun.codemodel.JCodeModel; import com.sun.codemodel.JDefinedClass; import com.sun.codemodel.JMethod; import com.sun.codemodel.JType; import com.sun.tools.xjc.BadCommandLineException; import com.sun.tools.xjc.Driver; import com.sun.tools.xjc.ErrorReceiver; import com.sun.tools.xjc.Options; import com.sun.tools.xjc.Plugin; import com.sun.tools.xjc.XJCListener; import com.sun.tools.xjc.api.Mapping; import com.sun.tools.xjc.api.Property; import com.sun.tools.xjc.api.S2JJAXBModel; import com.sun.tools.xjc.api.SchemaCompiler; import com.sun.tools.xjc.api.TypeAndAnnotation; import com.sun.tools.xjc.api.XJC; import com.sun.tools.xjc.reader.internalizer.AbstractReferenceFinderImpl; import com.sun.tools.xjc.reader.internalizer.DOMForest; import com.sun.tools.xjc.reader.internalizer.InternalizationLogic; import com.sun.tools.xjc.reader.xmlschema.parser.LSInputSAXWrapper; import com.sun.tools.xjc.reader.xmlschema.parser.XMLSchemaInternalizationLogic; import org.apache.cxf.Bus; import org.apache.cxf.catalog.OASISCatalogManager; import org.apache.cxf.catalog.OASISCatalogManagerHelper; import org.apache.cxf.common.i18n.Message; import org.apache.cxf.common.logging.LogUtils; import org.apache.cxf.common.util.ReflectionUtil; import org.apache.cxf.common.util.StringUtils; import org.apache.cxf.common.util.URIParserUtil; import org.apache.cxf.common.xmlschema.SchemaCollection; import org.apache.cxf.helpers.CastUtils; import org.apache.cxf.helpers.DOMUtils; import org.apache.cxf.helpers.FileUtils; import org.apache.cxf.resource.URIResolver; import org.apache.cxf.service.model.SchemaInfo; import org.apache.cxf.service.model.ServiceInfo; import org.apache.cxf.staxutils.StaxUtils; import org.apache.cxf.staxutils.W3CNamespaceContext; import org.apache.cxf.tools.common.ToolConstants; import org.apache.cxf.tools.common.ToolContext; import org.apache.cxf.tools.common.ToolException; import org.apache.cxf.tools.common.model.DefaultValueWriter; import org.apache.cxf.tools.util.ClassCollector; import org.apache.cxf.tools.util.JAXBUtils; import org.apache.cxf.tools.util.OutputStreamCreator; import org.apache.cxf.tools.wsdlto.core.DataBindingProfile; import org.apache.cxf.tools.wsdlto.core.DefaultValueProvider; import org.apache.cxf.tools.wsdlto.core.RandomValueProvider; import org.apache.cxf.wsdl.WSDLConstants; import org.apache.ws.commons.schema.XmlSchema; import org.apache.ws.commons.schema.XmlSchemaSerializer; import org.apache.ws.commons.schema.XmlSchemaSerializer.XmlSchemaSerializerException; public class JAXBDataBinding implements DataBindingProfile { static final String XJCVERSION; static { VersionDetectListener listener = new VersionDetectListener(); try { Driver.run(new String[] {"-version"}, listener); } catch (BadCommandLineException e) { // } XJCVERSION = listener.getVersion(); } static final class VersionDetectListener extends XJCListener { private String s = "2.1"; VersionDetectListener() { } public String getVersion() { return s; } public void error(SAXParseException exception) { } public void fatalError(SAXParseException exception) { } public void warning(SAXParseException exception) { } public void info(SAXParseException exception) { } public void message(String msg) { if (msg.contains(" ")) { msg = msg.substring(msg.indexOf(' ')).trim(); } if (!StringUtils.isEmpty(msg)) { s = msg; } } } public static class LocationFilterReader extends StreamReaderDelegate { boolean isImport; boolean isInclude; int locIdx = -1; OASISCatalogManager catalog; LocationFilterReader(XMLStreamReader read, OASISCatalogManager catalog) { super(read); this.catalog = catalog; } public int next() throws XMLStreamException { int i = super.next(); if (i == XMLStreamReader.START_ELEMENT) { QName qn = super.getName(); isInclude = qn.equals(WSDLConstants.QNAME_SCHEMA_INCLUDE); isImport = qn.equals(WSDLConstants.QNAME_SCHEMA_IMPORT); if (isImport) { findLocation(); } else { locIdx = -1; } } else { isImport = false; locIdx = -1; } return i; } public int nextTag() throws XMLStreamException { int i = super.nextTag(); if (i == XMLStreamReader.START_ELEMENT) { QName qn = super.getName(); isInclude = qn.equals(WSDLConstants.QNAME_SCHEMA_INCLUDE); isImport = qn.equals(WSDLConstants.QNAME_SCHEMA_IMPORT); if (isImport) { findLocation(); } else { locIdx = -1; } } else { isImport = false; locIdx = -1; } return i; } private void findLocation() { locIdx = -1; for (int x = super.getAttributeCount(); x > 0; --x) { String nm = super.getAttributeLocalName(x - 1); if ("schemaLocation".equals(nm)) { locIdx = x - 1; } } } public int getAttributeCount() { int i = super.getAttributeCount(); if (locIdx != -1) { --i; } return i; } private int mapIdx(int index) { if (locIdx != -1 && index >= locIdx) { ++index; } return index; } private String mapSchemaLocation(String target) { //See http://java.net/jira/browse/JAXB-925 if (this.getLocation().getSystemId().startsWith("jar:") && XJCVERSION.startsWith("2.2")) { return target; } return JAXBDataBinding.mapSchemaLocation(target, this.getLocation().getSystemId(), catalog); } public String getAttributeValue(String namespaceURI, String localName) { if (isInclude && "schemaLocation".equals(localName)) { return mapSchemaLocation(super.getAttributeValue(namespaceURI, localName)); } return super.getAttributeValue(namespaceURI, localName); } public String getAttributeValue(int index) { if (isInclude) { String n = getAttributeLocalName(index); if ("schemaLocation".equals(n)) { return mapSchemaLocation(super.getAttributeValue(index)); } } return super.getAttributeValue(mapIdx(index)); } public QName getAttributeName(int index) { return super.getAttributeName(mapIdx(index)); } public String getAttributePrefix(int index) { return super.getAttributePrefix(mapIdx(index)); } public String getAttributeNamespace(int index) { return super.getAttributeNamespace(mapIdx(index)); } public String getAttributeLocalName(int index) { return super.getAttributeLocalName(mapIdx(index)); } public String getAttributeType(int index) { return super.getAttributeType(mapIdx(index)); } public boolean isAttributeSpecified(int index) { return super.isAttributeSpecified(mapIdx(index)); } } private static final Logger LOG = LogUtils.getL7dLogger(JAXBDataBinding.class); private static final Set<String> DEFAULT_TYPE_MAP = new HashSet<>(); private static final Map<String, String> JLDEFAULT_TYPE_MAP = new HashMap<>(); private S2JJAXBModel rawJaxbModelGenCode; private ToolContext context; private DefaultValueProvider defaultValues; private boolean initialized; private JAXBBindErrorListener listener; static { DEFAULT_TYPE_MAP.add("boolean"); DEFAULT_TYPE_MAP.add("int"); DEFAULT_TYPE_MAP.add("long"); DEFAULT_TYPE_MAP.add("short"); DEFAULT_TYPE_MAP.add("byte"); DEFAULT_TYPE_MAP.add("float"); DEFAULT_TYPE_MAP.add("double"); DEFAULT_TYPE_MAP.add("char"); DEFAULT_TYPE_MAP.add("java.lang.String"); DEFAULT_TYPE_MAP.add("javax.xml.namespace.QName"); DEFAULT_TYPE_MAP.add("java.net.URI"); DEFAULT_TYPE_MAP.add("java.math.BigInteger"); DEFAULT_TYPE_MAP.add("java.math.BigDecimal"); DEFAULT_TYPE_MAP.add("javax.xml.datatype.XMLGregorianCalendar"); DEFAULT_TYPE_MAP.add("javax.xml.datatype.Duration"); JLDEFAULT_TYPE_MAP.put("java.lang.Character", "char"); JLDEFAULT_TYPE_MAP.put("java.lang.Boolean", "boolean"); JLDEFAULT_TYPE_MAP.put("java.lang.Integer", "int"); JLDEFAULT_TYPE_MAP.put("java.lang.Long", "long"); JLDEFAULT_TYPE_MAP.put("java.lang.Short", "short"); JLDEFAULT_TYPE_MAP.put("java.lang.Byte", "byte"); JLDEFAULT_TYPE_MAP.put("java.lang.Float", "float"); JLDEFAULT_TYPE_MAP.put("java.lang.Double", "double"); DEFAULT_TYPE_MAP.addAll(JLDEFAULT_TYPE_MAP.keySet()); } private void checkEncoding(ToolContext c) { String encoding = (String)c.get(ToolConstants.CFG_ENCODING); if (encoding != null) { try { CodeWriter.class.getDeclaredField("encoding"); } catch (Throwable t) { c.remove(ToolConstants.CFG_ENCODING); String fenc = System.getProperty("file.encoding"); if (!encoding.equals(fenc)) { LOG.log(Level.WARNING, "JAXB_NO_ENCODING_SUPPORT", new String[] {Driver.getBuildID(), fenc}); } } } } public void initialize(ToolContext c) throws ToolException { this.context = c; checkEncoding(c); SchemaCompiler schemaCompiler = XJC.createSchemaCompiler(); Bus bus = context.get(Bus.class); OASISCatalogManager catalog = bus.getExtension(OASISCatalogManager.class); Options opts = null; opts = getOptions(schemaCompiler); hackInNewInternalizationLogic(schemaCompiler, catalog, opts); ClassCollector classCollector = context.get(ClassCollector.class); ClassNameAllocatorImpl allocator = new ClassNameAllocatorImpl(classCollector, c.optionSet(ToolConstants.CFG_AUTORESOLVE)); schemaCompiler.setClassNameAllocator(allocator); listener = new JAXBBindErrorListener(context.isVerbose(), context.getErrorListener()); schemaCompiler.setErrorListener(listener); // Collection<SchemaInfo> schemas = serviceInfo.getSchemas(); List<InputSource> jaxbBindings = context.getJaxbBindingFile(); SchemaCollection schemas = (SchemaCollection) context.get(ToolConstants.XML_SCHEMA_COLLECTION); List<String> args = new ArrayList<>(); if (context.get(ToolConstants.CFG_NO_ADDRESS_BINDING) == null) { //hard code to enable jaxb extensions args.add("-extension"); String name = "/org/apache/cxf/tools/common/jaxb/W3CEPRJaxbBinding.xml"; if (isJAXB22()) { name = "/org/apache/cxf/tools/common/jaxb/W3CEPRJaxbBinding_jaxb22.xml"; } URL bindingFileUrl = getClass().getResource(name); InputSource ins = new InputSource(bindingFileUrl.toString()); opts.addBindFile(ins); } if (context.get(ToolConstants.CFG_XJC_ARGS) != null) { Object o = context.get(ToolConstants.CFG_XJC_ARGS); if (o instanceof String) { o = new String[] {(String)o}; } String[] xjcArgss = (String[])o; for (String xjcArgs : xjcArgss) { StringTokenizer tokenizer = new StringTokenizer(xjcArgs, ",", false); while (tokenizer.hasMoreTokens()) { String arg = tokenizer.nextToken(); args.add(arg); LOG.log(Level.FINE, "xjc arg:" + arg); } } } if (context.get(ToolConstants.CFG_NO_ADDRESS_BINDING) == null || context.get(ToolConstants.CFG_XJC_ARGS) != null) { try { // keep parseArguments happy, supply dummy required command-line // opts opts.addGrammar(new InputSource("null")); opts.parseArguments(args.toArray(new String[args.size()])); } catch (BadCommandLineException e) { StringBuilder msg = new StringBuilder("XJC reported 'BadCommandLineException' for -xjc argument:"); for (String arg : args) { msg.append(arg + " "); } LOG.log(Level.FINE, msg.toString(), e); if (opts != null) { String pluginUsage = getPluginUsageString(opts); msg.append(System.getProperty("line.separator")); if (args.contains("-X")) { throw new ToolException(pluginUsage, e); } else { msg.append(pluginUsage); } } throw new ToolException(msg.toString(), e); } } if (context.optionSet(ToolConstants.CFG_MARK_GENERATED)) { // Add the @Generated annotation in the Java files generated. This is done by passing // '-mark-generated' attribute to jaxb xjc. try { opts.parseArgument(new String[] {"-mark-generated" }, 0); } catch (BadCommandLineException e) { LOG.log(Level.SEVERE, e.getMessage()); throw new ToolException(e); } } addSchemas(opts, schemaCompiler, schemas); addBindingFiles(opts, jaxbBindings, schemas); for (String ns : context.getNamespacePackageMap().keySet()) { File file = JAXBUtils.getPackageMappingSchemaBindingFile(ns, context.mapPackageName(ns)); try { InputSource ins = new InputSource(file.toURI().toString()); schemaCompiler.parseSchema(ins); } finally { FileUtils.delete(file); } } if (context.getPackageName() != null) { schemaCompiler.setDefaultPackageName(context.getPackageName()); } rawJaxbModelGenCode = schemaCompiler.bind(); addedEnumClassToCollector(schemas, allocator); if (context.get(ToolConstants.CFG_DEFAULT_VALUES) != null) { String cname = (String)context.get(ToolConstants.CFG_DEFAULT_VALUES); if (StringUtils.isEmpty(cname)) { defaultValues = new RandomValueProvider(); } else { if (cname.charAt(0) == '=') { cname = cname.substring(1); } try { defaultValues = (DefaultValueProvider)Class.forName(cname).newInstance(); } catch (Exception e) { LOG.log(Level.SEVERE, e.getMessage()); throw new ToolException(e); } } } initialized = true; } private boolean isJAXB22() { return org.apache.cxf.common.jaxb.JAXBUtils.isJAXB22(); } private static final class ReferenceFinder extends AbstractReferenceFinderImpl { private Locator locator; private OASISCatalogManager catalog; ReferenceFinder(DOMForest parent, OASISCatalogManager cat) { super(parent); catalog = cat; } public void setDocumentLocator(Locator loc) { super.setDocumentLocator(loc); this.locator = loc; } protected String findExternalResource(String nsURI, String localName, Attributes atts) { if (XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(nsURI) && ("import".equals(localName) || "include".equals(localName))) { String s = atts.getValue("schemaLocation"); if (!StringUtils.isEmpty(s)) { //See http://java.net/jira/browse/JAXB-925 if (locator.getSystemId().startsWith("jar:") && XJCVERSION.startsWith("2.2")) { return s; } s = JAXBDataBinding.mapSchemaLocation(s, locator.getSystemId(), catalog); } return s; } return null; } } private void hackInNewInternalizationLogic(SchemaCompiler schemaCompiler, final OASISCatalogManager catalog, Options opts) { try { Field f = schemaCompiler.getClass().getDeclaredField("forest"); ReflectionUtil.setAccessible(f); XMLSchemaInternalizationLogic logic = new XMLSchemaInternalizationLogic() { public XMLFilterImpl createExternalReferenceFinder(DOMForest parent) { return new ReferenceFinder(parent, catalog); } }; Constructor<DOMForest> c = null; DOMForest forest = null; try { c = DOMForest.class.getConstructor(InternalizationLogic.class, Options.class); forest = c.newInstance(logic, opts); } catch (Throwable t) { c = DOMForest.class.getConstructor(InternalizationLogic.class); forest = c.newInstance(logic); } forest.setErrorHandler((ErrorReceiver)schemaCompiler); f.set(schemaCompiler, forest); } catch (Throwable ex) { //ignore } } private void addBindingFiles(Options opts, List<InputSource> jaxbBindings, SchemaCollection schemas) { for (InputSource binding : jaxbBindings) { XMLStreamReader r = StaxUtils.createXMLStreamReader(binding); try { StaxUtils.toNextTag(r); String s = r.getAttributeValue(null, "schemaLocation"); if (StringUtils.isEmpty(s)) { Document d = StaxUtils.read(r); XPath p = XPathFactory.newInstance().newXPath(); p.setNamespaceContext(new W3CNamespaceContext(d.getDocumentElement())); XPathExpression xpe = p.compile(d.getDocumentElement().getAttribute("node")); for (XmlSchema schema : schemas.getXmlSchemas()) { if (XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(schema.getTargetNamespace())) { continue; } Object src = getSchemaNode(schema, schemas); NodeList nodes = (NodeList)xpe.evaluate(src, XPathConstants.NODESET); if (nodes.getLength() > 0) { String key = schema.getSourceURI(); binding = convertToTmpInputSource(d.getDocumentElement(), key); opts.addBindFile(binding); binding = null; } } } } catch (Exception ex) { //ignore, just pass to jaxb } finally { try { r.close(); } catch (Exception ex) { //ignore } } if (binding != null) { opts.addBindFile(binding); } } } private Object getSchemaNode(XmlSchema schema, SchemaCollection schemaCollection) { XmlSchemaSerializer xser = new XmlSchemaSerializer(); xser.setExtReg(schemaCollection.getExtReg()); Document[] docs; try { docs = xser.serializeSchema(schema, false); } catch (XmlSchemaSerializerException e) { throw new RuntimeException(e); } return docs[0].getDocumentElement(); } private InputSource convertToTmpInputSource(Element ele, String schemaLoc) throws Exception { InputSource result = null; ele.setAttributeNS(null, "schemaLocation", schemaLoc); File tmpFile = FileUtils.createTempFile("jaxbbinding", ".xml"); StaxUtils.writeTo(ele, Files.newOutputStream(tmpFile.toPath())); result = new InputSource(URIParserUtil.getAbsoluteURI(tmpFile.getAbsolutePath())); tmpFile.deleteOnExit(); return result; } private void addSchemas(Options opts, SchemaCompiler schemaCompiler, SchemaCollection schemaCollection) { Set<String> ids = new HashSet<>(); @SuppressWarnings("unchecked") List<ServiceInfo> serviceList = (List<ServiceInfo>)context.get(ToolConstants.SERVICE_LIST); for (ServiceInfo si : serviceList) { for (SchemaInfo sci : si.getSchemas()) { String key = sci.getSystemId(); if (ids.contains(key)) { continue; } ids.add(key); } } Bus bus = context.get(Bus.class); OASISCatalogManager catalog = bus.getExtension(OASISCatalogManager.class); for (XmlSchema schema : schemaCollection.getXmlSchemas()) { if (XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(schema.getTargetNamespace())) { continue; } String key = schema.getSourceURI(); if (ids.contains(key)) { continue; } if (!key.startsWith("file:") && !key.startsWith("jar:")) { XmlSchemaSerializer xser = new XmlSchemaSerializer(); xser.setExtReg(schemaCollection.getExtReg()); Document[] docs; try { docs = xser.serializeSchema(schema, false); } catch (XmlSchemaSerializerException e) { throw new RuntimeException(e); } Element ele = docs[0].getDocumentElement(); if (context.fullValidateWSDL()) { String uri = null; try { uri = docs[0].getDocumentURI(); } catch (Throwable ex) { //ignore - DOM level 3 } validateSchema(ele, uri, catalog, schemaCollection); } ele = removeImportElement(ele, key, catalog); try { docs[0].setDocumentURI(key); } catch (Throwable t) { //ignore - DOM level 3 } InputSource is = new InputSource((InputStream)null); //key = key.replaceFirst("#types[0-9]+$", ""); is.setSystemId(key); is.setPublicId(key); opts.addGrammar(is); try { schemaCompiler.parseSchema(key, createNoCDATAReader(StaxUtils.createXMLStreamReader(ele, key))); } catch (XMLStreamException e) { throw new ToolException(e); } } } for (XmlSchema schema : schemaCollection.getXmlSchemas()) { if (XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(schema.getTargetNamespace())) { continue; } String key = schema.getSourceURI(); String tns = schema.getTargetNamespace(); String ltns = schema.getLogicalTargetNamespace(); // accepting also a null tns (e.g., reported by apache.ws.xmlschema for no-namespace) if (ids.contains(key) || (tns == null && !StringUtils.isEmpty(ltns))) { continue; } if (key.startsWith("file:") || key.startsWith("jar:")) { InputStream in = null; try { if (key.startsWith("file:")) { in = Files.newInputStream(new File(new URI(key)).toPath()); } else { in = new URL(key).openStream(); } XMLStreamReader reader = StaxUtils.createXMLStreamReader(key, in); reader = createNoCDATAReader(new LocationFilterReader(reader, catalog)); InputSource is = new InputSource(key); opts.addGrammar(is); schemaCompiler.parseSchema(key, reader); reader.close(); } catch (RuntimeException ex) { throw ex; } catch (Exception ex) { throw new RuntimeException(ex); } finally { if (in != null) { try { in.close(); } catch (IOException e) { //ignore } } } } } addSchemasForServiceInfos(catalog, serviceList, opts, schemaCompiler, schemaCollection); } private void addSchemasForServiceInfos(OASISCatalogManager catalog, List<ServiceInfo> serviceList, Options opts, SchemaCompiler schemaCompiler, SchemaCollection schemaCollection) { Set<String> ids = new HashSet<>(); for (ServiceInfo si : serviceList) { for (SchemaInfo sci : si.getSchemas()) { String key = sci.getSystemId(); if (ids.contains(key)) { continue; } ids.add(key); Element ele = sci.getElement(); if (context.fullValidateWSDL()) { validateSchema(ele, sci.getSystemId(), catalog, schemaCollection); } ele = removeImportElement(ele, key, catalog); InputSource is = new InputSource((InputStream)null); //key = key.replaceFirst("#types[0-9]+$", ""); is.setSystemId(key); is.setPublicId(key); opts.addGrammar(is); try { XMLStreamReader reader = createNoCDATAReader(StaxUtils.createXMLStreamReader(ele, key)); schemaCompiler.parseSchema(key, reader); } catch (XMLStreamException e) { throw new RuntimeException(e); } } } } private XMLStreamReader createNoCDATAReader(final XMLStreamReader reader) { return new StreamReaderDelegate(reader) { public int next() throws XMLStreamException { int i = super.next(); return i == XMLStreamReader.CDATA ? XMLStreamReader.CHARACTERS : i; } }; } private String getPluginUsageString(Options opts) { StringBuilder buf = new StringBuilder(); buf.append("\nAvailable plugin options:\n"); for (Plugin pl : opts.getAllPlugins()) { buf.append(pl.getUsage()); buf.append('\n'); } return buf.toString(); } // JAXB 'deprecates' getOptions, by which they mean that they reserve the right to change it. @SuppressWarnings("deprecation") private Options getOptions(SchemaCompiler schemaCompiler) throws ToolException { return schemaCompiler.getOptions(); } // JAXB bug. JAXB ClassNameCollector may not be invoked when generated // class is an enum. We need to use this method to add the missed file // to classCollector. private void addedEnumClassToCollector(SchemaCollection schemaCollection, ClassNameAllocatorImpl allocator) { //for (Element schemaElement : schemaList.values()) { for (XmlSchema schema : schemaCollection.getXmlSchemas()) { String targetNamespace = schema.getTargetNamespace(); if (StringUtils.isEmpty(targetNamespace)) { continue; } String packageName = context.mapPackageName(targetNamespace); if (!addedToClassCollector(packageName)) { allocator.assignClassName(packageName, "*"); } } } private boolean addedToClassCollector(String packageName) { ClassCollector classCollector = context.get(ClassCollector.class); Collection<String> files = classCollector.getGeneratedFileInfo(); for (String file : files) { int dotIndex = file.lastIndexOf("."); String sub = dotIndex <= 0 ? "" : file.substring(0, dotIndex - 1); if (sub.equals(packageName)) { return true; } } return false; } private boolean isSuppressCodeGen() { return context.optionSet(ToolConstants.CFG_SUPPRESS_GEN); } public void generate(ToolContext c) throws ToolException { if (!initialized) { initialize(c); } if (rawJaxbModelGenCode == null) { return; } if (c.getErrorListener().getErrorCount() > 0) { return; } try { String dir = (String)context.get(ToolConstants.CFG_OUTPUTDIR); TypesCodeWriter fileCodeWriter = new TypesCodeWriter(new File(dir), context.getExcludePkgList(), (String)context.get(ToolConstants.CFG_ENCODING), context.get(OutputStreamCreator.class)); S2JJAXBModel schem2JavaJaxbModel = rawJaxbModelGenCode; ClassCollector classCollector = context.get(ClassCollector.class); for (JClass cls : schem2JavaJaxbModel.getAllObjectFactories()) { classCollector.getTypesPackages().add(cls._package().name()); } JCodeModel jcodeModel = schem2JavaJaxbModel.generateCode(null, null); if (!isSuppressCodeGen()) { jcodeModel.build(fileCodeWriter); } context.put(JCodeModel.class, jcodeModel); for (String str : fileCodeWriter.getExcludeFileList()) { context.getExcludeFileList().add(str); } return; } catch (IOException e) { Message msg = new Message("FAIL_TO_GENERATE_TYPES", LOG); throw new ToolException(msg, e); } } public String getType(QName qname, boolean element) { TypeAndAnnotation typeAnno = rawJaxbModelGenCode.getJavaType(qname); if (element) { Mapping mapping = rawJaxbModelGenCode.get(qname); if (mapping != null) { typeAnno = mapping.getType(); } } if (typeAnno != null && typeAnno.getTypeClass() != null) { return typeAnno.getTypeClass().fullName(); } return null; } public String getWrappedElementType(QName wrapperElement, QName item) { Mapping mapping = rawJaxbModelGenCode.get(wrapperElement); if (mapping != null) { List<? extends Property> propList = mapping.getWrapperStyleDrilldown(); if (propList != null) { for (Property pro : propList) { if (pro.elementName().getNamespaceURI().equals(item.getNamespaceURI()) && pro.elementName().getLocalPart().equals(item.getLocalPart())) { return pro.type().fullName(); } } } } return null; } private Element removeImportElement(Element element, String sysId, OASISCatalogManager catalog) { List<Element> impElemList = DOMUtils.findAllElementsByTagNameNS(element, ToolConstants.SCHEMA_URI, "import"); List<Element> incElemList = DOMUtils.findAllElementsByTagNameNS(element, ToolConstants.SCHEMA_URI, "include"); boolean hasJAXB = DOMUtils.hasElementInNS(element, ToolConstants.NS_JAXB_BINDINGS); if (impElemList.size() == 0 && incElemList.size() == 0 && !hasJAXB) { return element; } element = (Element)cloneNode(element.getOwnerDocument(), element, true); impElemList = DOMUtils.findAllElementsByTagNameNS(element, ToolConstants.SCHEMA_URI, "import"); for (Element item : impElemList) { item.removeAttribute("schemaLocation"); } incElemList = DOMUtils.findAllElementsByTagNameNS(element, ToolConstants.SCHEMA_URI, "include"); for (Element elem : incElemList) { Attr val = elem.getAttributeNode("schemaLocation"); val.setNodeValue(mapSchemaLocation(val.getNodeValue(), sysId, catalog)); } if (hasJAXB) { //need to add ns and version String pfx = DOMUtils.getPrefix(element, ToolConstants.NS_JAXB_BINDINGS); if (StringUtils.isEmpty(pfx)) { pfx = DOMUtils.createNamespace(element, ToolConstants.NS_JAXB_BINDINGS); } element.setAttributeNS(ToolConstants.NS_JAXB_BINDINGS, pfx + ":version", "2.0"); } return element; } public Node cloneNode(Document document, Node node, boolean deep) throws DOMException { if (document == null || node == null) { return null; } int type = node.getNodeType(); if (node.getOwnerDocument() == document) { return node.cloneNode(deep); } Node clone; switch (type) { case Node.CDATA_SECTION_NODE: clone = document.createCDATASection(node.getNodeValue()); break; case Node.COMMENT_NODE: clone = document.createComment(node.getNodeValue()); break; case Node.ENTITY_REFERENCE_NODE: clone = document.createEntityReference(node.getNodeName()); break; case Node.ELEMENT_NODE: clone = document.createElement(node.getNodeName()); NamedNodeMap attributes = node.getAttributes(); for (int i = 0; i < attributes.getLength(); i++) { ((Element)clone).setAttributeNS(attributes.item(i).getNamespaceURI(), attributes.item(i).getNodeName(), attributes.item(i).getNodeValue()); } try { clone.setUserData("location", node.getUserData("location"), null); } catch (Throwable t) { //non DOM level 3 } break; case Node.TEXT_NODE: clone = document.createTextNode(node.getNodeValue()); break; default: return null; } if (deep && type == Node.ELEMENT_NODE) { Node child = node.getFirstChild(); while (child != null) { clone.appendChild(cloneNode(document, child, true)); child = child.getNextSibling(); } } return clone; } public void validateSchema(Element ele, String uri, final OASISCatalogManager catalog, final SchemaCollection schemaCollection) throws ToolException { SchemaFactory schemaFact = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); schemaFact.setResourceResolver(new LSResourceResolver() { public LSInput resolveResource(String type, String namespaceURI, String publicId, String systemId, String baseURI) { String s = JAXBDataBinding.mapSchemaLocation(systemId, baseURI, catalog); //System.out.println(namespaceURI + " " + systemId + " " + baseURI + " " + s); if (s == null) { XmlSchema sc = schemaCollection.getSchemaByTargetNamespace(namespaceURI); StringWriter writer = new StringWriter(); sc.write(writer); InputSource src = new InputSource(new StringReader(writer.toString())); src.setSystemId(sc.getSourceURI()); return new LSInputSAXWrapper(src); } return new LSInputSAXWrapper(new InputSource(s)); } }); DOMSource domSrc = new DOMSource(ele, uri); try { schemaFact.newSchema(domSrc); } catch (SAXException e) { if (e.getLocalizedMessage().indexOf("src-resolve.4.2") > -1) { //Ignore schema resolve error and do nothing } else { //e.printStackTrace(); throw new ToolException("Schema Error : " + e.getLocalizedMessage(), e); } } } public DefaultValueWriter createDefaultValueWriter(QName qname, boolean element) { if (defaultValues == null) { return null; } TypeAndAnnotation typeAnno = rawJaxbModelGenCode.getJavaType(qname); if (element) { Mapping mapping = rawJaxbModelGenCode.get(qname); if (mapping != null) { typeAnno = mapping.getType(); } } if (typeAnno != null && typeAnno.getTypeClass() instanceof JDefinedClass) { JDefinedClass dc = (JDefinedClass)typeAnno.getTypeClass(); if (dc.isAbstract()) { //no default values for abstract classes typeAnno = null; } } if (typeAnno != null) { final JType type = typeAnno.getTypeClass(); return new JAXBDefaultValueWriter(type); } return null; } public DefaultValueWriter createDefaultValueWriterForWrappedElement(QName wrapperElement, QName item) { if (defaultValues != null) { Mapping mapping = rawJaxbModelGenCode.get(wrapperElement); if (mapping != null) { List<? extends Property> propList = mapping.getWrapperStyleDrilldown(); for (Property pro : propList) { if (pro.elementName().getNamespaceURI().equals(item.getNamespaceURI()) && pro.elementName().getLocalPart().equals(item.getLocalPart())) { JType type = pro.type(); if (type instanceof JDefinedClass && ((JDefinedClass)type).isAbstract()) { //no default values for abstract classes return null; } return new JAXBDefaultValueWriter(pro.type()); } } } } return null; } private class JAXBDefaultValueWriter implements DefaultValueWriter { final JType type; JAXBDefaultValueWriter(JType tp) { type = tp; } public void writeDefaultValue(Writer writer, String indent, String path, String varName) throws IOException { path = path + "/" + varName; writeDefaultValue(writer, indent, path, varName, type); } public void writeDefaultValue(Writer writer, String indent, String path, String varName, JType tp) throws IOException { writer.write(tp.fullName()); writer.write(" "); writer.write(varName); writer.write(" = "); if (tp.isArray()) { writer.write("new "); writer.write(tp.fullName()); writer.write(" {};"); } else if (DEFAULT_TYPE_MAP.contains(tp.fullName())) { writeDefaultType(writer, tp, path); writer.write(";"); } else if (tp instanceof JDefinedClass) { JDefinedClass jdc = (JDefinedClass)tp; if (jdc.getClassType() == ClassType.ENUM) { //no way to get the field list as it's private with //no accessors :-( try { Field f = jdc.getClass().getDeclaredField("enumConstantsByName"); ReflectionUtil.setAccessible(f); Map<?, ?> map = (Map<?, ?>)f.get(jdc); Set<String> values = CastUtils.cast(map.keySet()); String first = defaultValues.chooseEnumValue(path, values); writer.write(tp.fullName()); writer.write("."); writer.write(first); writer.write(";"); } catch (Exception e) { IOException ex = new IOException(e.getMessage()); ex.initCause(e); throw ex; } } else if (jdc.isAbstract()) { writer.write("null;"); } else { writer.write("new "); writer.write(tp.fullName()); writer.write("();"); fillInFields(writer, indent, path, varName, jdc); } } else { boolean found = false; JType tp2 = tp.erasure(); try { Field f = tp2.getClass().getDeclaredField("_class"); ReflectionUtil.setAccessible(f); Class<?> cls = (Class<?>)f.get(tp2); if (List.class.isAssignableFrom(cls)) { found = true; writer.write("new "); writer.write(tp.fullName().replace("java.util.List", "java.util.ArrayList")); writer.write("();"); f = tp.getClass().getDeclaredField("args"); ReflectionUtil.setAccessible(f); List<JClass> lcl = CastUtils.cast((List<?>)f.get(tp)); JClass cl = lcl.get(0); int cnt = defaultValues.getListLength(path + "/" + varName); for (int x = 0; x < cnt; x++) { writer.write("\n"); writer.write(indent); writeDefaultValue(writer, indent, path + "/" + varName + "Val", varName + "Val" + cnt, cl); writer.write("\n"); writer.write(indent); writer.write(varName); writer.write(".add("); writer.write(varName + "Val" + cnt); writer.write(");"); } } } catch (Exception e) { //ignore } if (!found) { //System.err.println("No idea what to do with " + tp.fullName()); //System.err.println(" class " + tp.getClass().getName()); writer.write("null;"); } } } public void fillInFields(Writer writer, String indent, String path, String varName, JDefinedClass tp) throws IOException { JClass sp = tp._extends(); if (sp instanceof JDefinedClass) { fillInFields(writer, indent, path, varName, (JDefinedClass)sp); } Collection<JMethod> methods = tp.methods(); for (JMethod m : methods) { if (m.name().startsWith("set")) { writer.write("\n"); writer.write(indent); if (DEFAULT_TYPE_MAP.contains(m.listParamTypes()[0].fullName())) { writer.write(varName); writer.write("."); writer.write(m.name()); writer.write("("); writeDefaultType(writer, m.listParamTypes()[0], path + "/" + m.name().substring(3)); writer.write(");"); } else { int idx = path.indexOf("/" + m.name().substring(3) + "/"); if (idx > 0) { idx = path.indexOf("/" + m.name().substring(3) + "/", idx + 1); } boolean hasTwo = idx > 0; if (!hasTwo) { writeDefaultValue(writer, indent, path + "/" + m.name().substring(3), varName + m.name().substring(3), m.listParamTypes()[0]); writer.write("\n"); } writer.write(indent); writer.write(varName); writer.write("."); writer.write(m.name()); writer.write("("); if (!hasTwo) { writer.write(varName + m.name().substring(3)); } else { writer.write("null"); } writer.write(");"); } } else if (m.type().fullName().startsWith("java.util.List")) { writer.write("\n"); writer.write(indent); writeDefaultValue(writer, indent, path + "/" + m.name().substring(3), varName + m.name().substring(3), m.type()); writer.write("\n"); writer.write(indent); writer.write(varName); writer.write("."); writer.write(m.name()); writer.write("().addAll("); writer.write(varName + m.name().substring(3)); writer.write(");"); } } } private void writeDefaultType(Writer writer, JType t, String path) throws IOException { String name = t.fullName(); writeDefaultType(writer, name, path); } private void writeDefaultType(Writer writer, String name, String path) throws IOException { if (JLDEFAULT_TYPE_MAP.containsKey(name)) { writer.append(name.substring("java.lang.".length())).append(".valueOf("); writeDefaultType(writer, JLDEFAULT_TYPE_MAP.get(name), path); writer.append(")"); } else if ("boolean".equals(name)) { writer.append(defaultValues.getBooleanValue(path) ? "true" : "false"); } else if ("int".equals(name)) { writer.append(Integer.toString(defaultValues.getIntValue(path))); } else if ("long".equals(name)) { writer.append(Long.toString(defaultValues.getLongValue(path))).append("l"); } else if ("short".equals(name)) { writer.append("(short)").append(Short.toString(defaultValues.getShortValue(path))); } else if ("byte".equals(name)) { writer.append("(byte)").append(Byte.toString(defaultValues.getByteValue(path))); } else if ("float".equals(name)) { writer.append(Float.toString(defaultValues.getFloatValue(path))).append("f"); } else if ("double".equals(name)) { writer.append(Double.toString(defaultValues.getDoubleValue(path))); } else if ("char".equals(name)) { writer.append("(char)").append(Character.toString(defaultValues.getCharValue(path))); } else if ("java.lang.String".equals(name)) { writer.append("\"") .append(defaultValues.getStringValue(path)) .append("\""); } else if ("javax.xml.namespace.QName".equals(name)) { QName qn = defaultValues.getQNameValue(path); writer.append("new javax.xml.namespace.QName(\"") .append(qn.getNamespaceURI()) .append("\", \"") .append(qn.getLocalPart()) .append("\")"); } else if ("java.net.URI".equals(name)) { writer.append("new java.net.URI(\"") .append(defaultValues.getURIValue(path).toASCIIString()) .append("\")"); } else if ("java.math.BigInteger".equals(name)) { writer.append("new java.math.BigInteger(\"") .append(defaultValues.getBigIntegerValue(path).toString()) .append("\")"); } else if ("java.math.BigDecimal".equals(name)) { writer.append("new java.math.BigDecimal(\"") .append(defaultValues.getBigDecimalValue(path).toString()) .append("\")"); } else if ("javax.xml.datatype.XMLGregorianCalendar".equals(name)) { writer.append("javax.xml.datatype.DatatypeFactory.newInstance().newXMLGregorianCalendar(\"") .append(defaultValues.getXMLGregorianCalendarValueString(path)) .append("\")"); } else if ("javax.xml.datatype.Duration".equals(name)) { writer.append("javax.xml.datatype.DatatypeFactory.newInstance().newDuration(\"") .append(defaultValues.getDurationValueString(path)) .append("\")"); } } } private static String mapSchemaLocation(String target, String base, OASISCatalogManager catalog) { try { String resolvedLocation = new OASISCatalogManagerHelper().resolve(catalog, target, base); if (resolvedLocation != null) { return resolvedLocation; } } catch (Exception ex) { //ignore } try { URIResolver resolver = new URIResolver(base, target); if (resolver.isResolved()) { target = resolver.getURI().toString(); } } catch (Exception ex) { //ignore } return target; } }